package com.an.trip.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.an.common.constant.TripConstants;
import com.an.common.core.domain.BaseEntity;
import com.an.common.core.domain.PageQuery;
import com.an.common.core.page.TableDataInfo;
import com.an.common.exception.trip.TripException;
import com.an.common.utils.StreamUtils;
import com.an.common.utils.StringUtils;
import com.an.trip.domain.TripDailyRecord;
import com.an.trip.domain.TripMember;
import com.an.trip.domain.bo.TripDailyRecordBo;
import com.an.trip.domain.vo.TripDailyRecordVo;
import com.an.trip.mapper.TripDailyRecordMapper;
import com.an.trip.mapper.TripMemberMapper;
import com.an.trip.service.ITripDailyRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 行程每日记录Service业务层处理
 *
 * @author Ann
 * @date 2024-12-04
 */
@RequiredArgsConstructor
@Service
public class TripDailyRecordServiceImpl implements ITripDailyRecordService {

    private final TripDailyRecordMapper baseMapper;
    private final TripMemberMapper tripMemberMapper;

    /**
     * 查询行程每日记录
     */
    @Override
    public TripDailyRecordVo queryById(Long tripId) {
        return baseMapper.selectVoById(tripId);
    }

    /**
     * 查询行程每日记录列表
     */
    @Override
    public TableDataInfo<TripDailyRecordVo> queryPageList(TripDailyRecordBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TripDailyRecord> lqw = buildQueryWrapper(bo);
        Page<TripDailyRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<TripDailyRecordVo> records = result.getRecords();
        // 获取指派人和司机名字，并赋值
        queryAssignerAndDriverName(records);
        return TableDataInfo.build(result);
    }

    /**
     * 查询分配者和司机名称
     *
     * @param records 记录
     * @author ANH
     * @date 2024/12/07
     */
    private void queryAssignerAndDriverName(List<TripDailyRecordVo> records) {
        Set<Long> assignersAndDriverIds = records.stream()
                .flatMap(record -> Stream.of(record.getAssigner(), record.getDriver()))
                .collect(Collectors.toSet());
        List<TripMember> tripMembers = tripMemberMapper.selectList(new LambdaQueryWrapper<TripMember>()
                .in(CollUtil.isNotEmpty(assignersAndDriverIds), TripMember::getMemberId, assignersAndDriverIds));
        Map<Long, String> memberIdNameMap = StreamUtils.toMap(tripMembers, TripMember::getMemberId, TripMember::getMemberName);
        for (TripDailyRecordVo record : records) {
            String assignerName = memberIdNameMap.get(record.getAssigner());
            String driverName = memberIdNameMap.get(record.getDriver());
            if (StringUtils.isNotBlank(assignerName)) {
                record.setAssignerName(assignerName);
            }
            if (StringUtils.isNotBlank(driverName)) {
                record.setDriverName(driverName);
            }
        }
    }

    /**
     * 查询行程每日记录列表
     */
    @Override
    public List<TripDailyRecordVo> queryList(TripDailyRecordBo bo) {
        LambdaQueryWrapper<TripDailyRecord> lqw = buildQueryWrapper(bo);
        List<TripDailyRecordVo> tripDailyRecordVos = baseMapper.selectVoList(lqw);
        queryAssignerAndDriverName(tripDailyRecordVos);
        return tripDailyRecordVos;
    }

    private LambdaQueryWrapper<TripDailyRecord> buildQueryWrapper(TripDailyRecordBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TripDailyRecord> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getAssigner() != null, TripDailyRecord::getAssigner, bo.getAssigner());
        lqw.eq(bo.getDriver() != null, TripDailyRecord::getDriver, bo.getDriver());
        lqw.like(StringUtils.isNotBlank(bo.getDepartureLocation()), TripDailyRecord::getDepartureLocation, bo.getDepartureLocation());
        lqw.like(StringUtils.isNotBlank(bo.getDestination()), TripDailyRecord::getDestination, bo.getDestination());
        lqw.eq(bo.getMileage() != null, TripDailyRecord::getMileage, bo.getMileage());
        lqw.between(params.get("beginStartTime") != null && params.get("endStartTime") != null,
                TripDailyRecord::getStartTime, params.get("beginStartTime"), params.get("endStartTime"));
        lqw.between(params.get("beginEndTime") != null && params.get("beginEndTime") != null,
                TripDailyRecord::getEndTime, params.get("beginEndTime"), params.get("endEndTime"));
        lqw.eq(bo.getFare() != null, TripDailyRecord::getFare, bo.getFare());
        lqw.eq(StringUtils.isNotBlank(bo.getSettleStatus()), TripDailyRecord::getSettleStatus, bo.getSettleStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getSettledBy()), TripDailyRecord::getSettledBy, bo.getSettledBy());
        lqw.orderByDesc(BaseEntity::getCreateTime);
        return lqw;
    }

    /**
     * 新增行程每日记录
     */
    @Override
    public Boolean insertByBo(TripDailyRecordBo bo) {
        TripDailyRecord add = BeanUtil.toBean(bo, TripDailyRecord.class);
        add.setParentId(0L);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setTripId(add.getTripId());
        }
        return flag;
    }

    /**
     * 修改行程每日记录
     */
    @Override
    public Boolean updateByBo(TripDailyRecordBo bo) {
        TripDailyRecord tripDailyRecord = BeanUtil.toBean(bo, TripDailyRecord.class);
        validEntityBeforeSave(tripDailyRecord);
        checkSettleStatus(Arrays.asList(bo.getTripId()));
        return baseMapper.updateById(tripDailyRecord) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TripDailyRecord entity) {
        // 计算出行天数，包含结束日期
        Date startTime = entity.getStartTime();
        Date endTime = entity.getEndTime();
        if (startTime.after(endTime)) {
            throw new TripException("trip.dailyrecord.add.date.error");
        }
        long days = DateUtil.betweenDay(startTime, endTime, true) + 1;
        entity.setDays(days);
    }

    /**
     * 批量删除行程每日记录
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 按 ID 结算
     *
     * @param ids 列表
     * @return {@link Boolean }
     * @author ANH
     * @date 2024/12/07
     */
    @Override
    public Boolean settleByIds(List<Long> ids) {
        // 检查是否包含已结账的数据
        checkSettleStatus(ids);
        List<TripDailyRecord> tripDailyRecords = ids.stream().map(tripId -> {
            TripDailyRecord tripDailyRecord = new TripDailyRecord();
            tripDailyRecord.setTripId(tripId);
            tripDailyRecord.setSettleStatus(TripConstants.SETTLED_STATUS);
            return tripDailyRecord;
        }).collect(Collectors.toList());
        return baseMapper.updateBatchById(tripDailyRecords);
    }

    /**
     * 委托
     *
     * @param recordBo 记录 bo
     * @return {@link Boolean }
     * @author ANH
     * @date 2025/01/03
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delegate(TripDailyRecordBo recordBo) {
        Long tripId = recordBo.getTripId();

        Long driver = recordBo.getDriver();
        BigDecimal fare = recordBo.getFare();
        String remark = recordBo.getRemark();
        String settleStatus = recordBo.getSettleStatus();

        TripDailyRecord tripDailyRecord = baseMapper.selectById(tripId);
        if (!tripDailyRecord.getDelegateStatus().equals(TripConstants.UN_DELEGATED)) {
            throw new TripException("trip.dailyrecord.delegated.error");
        }
        if (ObjectUtil.isNull(tripDailyRecord)) {
            throw new TripException("trip.dailyrecord.not.exist");
        }
        TripDailyRecord delegateTrip = BeanUtil.copyProperties(tripDailyRecord, TripDailyRecord.class, "tripId");
        // 委派操作，指派人必须为当前行程的出车人
        delegateTrip.setAssigner(tripDailyRecord.getDriver());
        delegateTrip.setParentId(tripId);
        delegateTrip.setDriver(driver);
        delegateTrip.setFare(fare);
        delegateTrip.setRemark(remark);
        // 设置被委托行程
        delegateTrip.setDelegateStatus(TripConstants.BE_DELEGATED);
        delegateTrip.setSettleStatus(settleStatus);
        baseMapper.insert(delegateTrip);
        // 设置本行程为已委托
        tripDailyRecord.setDelegateStatus(TripConstants.DELEGATED);

        return baseMapper.updateById(tripDailyRecord) > 0;
    }

    /**
     * 查询原始信息
     *
     * @param tripId 行程 ID
     * @return {@link TripDailyRecordVo }
     * @author ANH
     * @date 2025/01/03
     */
    @Override
    public TripDailyRecordVo queryOriginalInfo(Long tripId) {
        TripDailyRecord tripDailyRecord = baseMapper.selectById(tripId);
        Long parentId = tripDailyRecord.getParentId();
        checkDelegateStatus(tripDailyRecord);
        TripDailyRecordVo tripDailyRecordVo = baseMapper.selectVoById(parentId);
        buildDelegateInfoOrOriginalInfo(tripDailyRecordVo);
        return tripDailyRecordVo;
    }

    /**
     * 检查受托人状态
     *
     * @param tripDailyRecord 行程每日记录
     * @author ANH
     * @date 2025/01/03
     */
    private void checkDelegateStatus(TripDailyRecord tripDailyRecord) {
        if(tripDailyRecord.getDelegateStatus().equals(TripConstants.UN_DELEGATED)) {
            throw new TripException("trip.dailyrecord.not.exist");
        }
    }

    /**
     * 查询受托人行程信息
     *
     * @param tripId 行程 ID
     * @return {@link TripDailyRecordVo }
     * @author ANH
     * @date 2025/01/03
     */
    @Override
    public TripDailyRecordVo queryDelegateInfo(Long tripId) {
        TripDailyRecord tripDailyRecord = baseMapper.selectById(tripId);
        checkDelegateStatus(tripDailyRecord);
        TripDailyRecordVo tripDailyRecordVo = baseMapper.selectVoOne(new LambdaQueryWrapper<TripDailyRecord>()
                .eq(TripDailyRecord::getParentId,tripId));
        buildDelegateInfoOrOriginalInfo(tripDailyRecordVo);
        return tripDailyRecordVo;
    }

    /**
     * 生成代理信息或原始信息
     *
     * @param tripDailyRecordVo 行程每日记录 VO
     * @author ANH
     * @date 2025/01/03
     */
    private void buildDelegateInfoOrOriginalInfo(TripDailyRecordVo tripDailyRecordVo) {
        List<Long> memberIds = Arrays.asList(tripDailyRecordVo.getAssigner(), tripDailyRecordVo.getDriver());
        List<TripMember> tripMembers = tripMemberMapper.selectList(new LambdaQueryWrapper<TripMember>()
                .in(TripMember::getMemberId, memberIds));
        Map<Long, String> memberIdNameMap = StreamUtils.toMap(tripMembers, TripMember::getMemberId, TripMember::getMemberName);
        tripDailyRecordVo.setAssignerName(memberIdNameMap.get(tripDailyRecordVo.getAssigner()));
        tripDailyRecordVo.setDriverName(memberIdNameMap.get(tripDailyRecordVo.getDriver()));
    }


    /**
     * 检查 Settle 状态
     *
     * @param ids 列表
     * @author ANH
     * @date 2024/12/07
     */
    private void checkSettleStatus(List<Long> ids) {
        List<TripDailyRecord> tripDailyRecords = baseMapper.selectList(new LambdaQueryWrapper<TripDailyRecord>()
                .in(CollUtil.isNotEmpty(ids), TripDailyRecord::getTripId, ids));
        for (TripDailyRecord tripDailyRecord : tripDailyRecords) {
            if (TripConstants.SETTLED_STATUS.equals(tripDailyRecord.getSettleStatus())) {
                throw new TripException("trip.dailyrecord.settle.error");
            }
        }
    }

    public static void main(String[] args) {
        // 计算出行天数，包含结束日期
        // 定义开始日期和结束日期
        Date startTime = DateUtil.parse("2024-12-06");
        Date endTime = DateUtil.parse("2024-12-05");
        long l = DateUtil.betweenDay(startTime, endTime, true) + 1;
        System.out.println(l);
    }

}
